<style lang="less">
.area-tree {
    & {
        width: 100%;
        // padding-bottom: 200px;
        min-height: 300px;
        max-height: 500px;
        overflow: auto;
    }

    .divider {
        margin-left: 4px;
        margin-right: 4px;
    }
}
</style>
<template>
    <ZkModal :title="title" :size="'xs'" :visible="visible" @cancel="handleCancel" @ok="handleOk">
        <div class="area-tree">
            <a-tree :default-expand-all="false" :blockNode="true" :selected-keys="selectedKeys" :tree-data="treeData" :loadData="onLoadData" :loadedKeys="loadedKeys" :expandedKeys="expandedKeys" :draggable="false" @select="onTreeSelect" @expand="onExpand">
                <template slot="custom" slot-scope="item">
                        <div v-if="hasOper">
                            <div v-if="!item.isRoot">
                                <span>{{ item.title }} </span>
                                <zk-btn @click.stop="addNode(item)">新增</zk-btn>
                                <a-divider type="vertical" class="divider" />
                                <zk-btn @click.stop="showNodeDetail(item)">查看</zk-btn>
                                <a-divider type="vertical" class="divider" />
                                <zk-btn @click.stop="showNodeEdit(item)">修改</zk-btn>
                                <a-divider type="vertical" class="divider" />
                                <zk-btn @click.stop="delNode(item)">删除</zk-btn>
                                <a-divider type="vertical" class="divider" v-if="!item.isFirst" />
                                <zk-btn @click.stop="upNode(item)" v-if="!item.isFirst">上移</zk-btn>
                                <a-divider type="vertical" class="divider" v-if="!item.isLast" />
                                <zk-btn @click.stop="downNode(item)" v-if="!item.isLast">下移</zk-btn>
                            </div>
                            <div v-else>
                                <span>{{ item.title }} </span>
                                <zk-btn @click.stop="addNode(item)">新增</zk-btn>
                            </div>
                        </div>
                        <div v-else>
                            <span>{{ item.title }} </span>
                        </div>
                </template>
            </a-tree>
        </div>
    </ZkModal>
</template>
<script>
console.log(123123);
import { queryRegion, queryRegionTree } from '@/api/base';
import { delCategoryTreeNode, queryCategoryTree, updateCategoryTreeNodeSort } from '@/api/common';
import ZkModal from '@/appBase/ZkModal.vue';
export default {
        components: {
        ZkModal
    },
    data() {
        return {
            title:'城市选择',
            rootKey:'0',
            visible:false,
            // 选中的
            selectedKeys: [],
            // 状态树
            treeData: [],
            // 展开的树节点
            expandedKeys: [],
            loadedKeys: [],
            // 当前选中节点
            selectedData: null,
            hasOper:false,
            // 可选层级 1.省 2.市 3.区
            canSelectedLevels:[1,2,3]
        }
    },
    methods: {
        /**
         * 显示
         * @param {Object} params
         * @param {Array} params.canSelectedLevels 可选层级 1.省 2.市 3.区 
         * @param {Function} params.onOk  选择完成回调 
         */
        show(params){
            Object.assign(this,this.$options.data());
            this.onOk = params.onOk;
            if(params.canSelectedLevels){ 
                this.canSelectedLevels = params.canSelectedLevels.map(i => parseInt(''+i)).sort();
            }
            this.visible = true;
            this.expandedKeys = [this.rootKey];
            this.refresh();
        },
        async refresh() {
            let title = '中华人民共和国';
            // 城市选择
            let arr = await queryRegion({
                parentId: 0
            }) || [];
            this.treeData = [
                {
                    title,
                    key: this.rootKey,
                    scopedSlots: {
                        title: 'custom',
                    },
                    isRoot: true,
                    children: nodeDataToVMNodeData(arr,this),
                    isLeaf: false
                }
            ];
        },
        async onLoadData(node) {
            try {
                const item = node.dataRef;
                if (item.children) {
                    return;
                }
                let arr = await queryRegion({
                    parentId: item.id
                });
                if (!arr) {
                    return;
                }
                item.children = nodeDataToVMNodeData(arr,this);
                this.treeData = [...this.treeData];
            } catch (error) {
                console.log(error);
                return;
            }
        },
        onTreeSelect(selectedKeys, e) {
            this.setTreeSelected(selectedKeys);
            if (e.selected) {
                if(!e.node.isLeaf)this.expandedKeys  = [...this.expandedKeys,e.node.dataRef.id];
                if(this.canSelectedLevels.includes(e.node.dataRef.level)){
                    this.selectedData = e.node.dataRef;
                }
                // this.$emit('selected', e.node.dataRef);
            } else {
                this.selectedData = null;
                // this.$emit('selected', null);
            }
        },
        onExpand(expandedKeys) {
            this.expandedKeys = expandedKeys;
        },
        setTreeSelected(selectedKeys) {
            this.selectedKeys = [...selectedKeys];
            if (selectedKeys.length > 0 && selectedKeys[0] == 0) {
                selectedKeys[0] = null;
            }
        },

        addNode(item) {
            this.$refs.edit.show({
                parentId: item.key == this.rootKey ? '0' : item.key,
                parentName: item.title,
                type: this.type,
                onOk: async () => {
                    await this.refresh();
                    this.expandedKeys.push(item.key);
                }
            });
        },
        showNodeDetail(item) {
            this.$refs.detail.show({
                id: item.key
            });
        },
        showNodeEdit(item) {
            this.$refs.edit.show({
                id: item.key,
                onOk: async () => {
                    await this.refresh();
                }
            });
        },
        delNode(item) {
            if (item.children && item.children.length > 0) {
                this.$warning({
                    title: '提示',
                    content: `当前分类包含下级分类，不可被删除！`
                })
                return;
            }
            this.$confirm({
                title: '提示',
                content: `确定要删除当前分类？`,
                onOk: async () => {
                    await delCategoryTreeNode({ id: item.id });
                    await this.refresh();
                }
            });
        },
        async upNode(item) {
            const res = queryNodeInTree(item.key, { children: this.treeData });
            if (!res) {
                throw Error('未找到节点！', item);
            }
            const arr = res.pNode.children;
            const index = arr.findIndex(i => i.key == item.key);
            const node = arr[index];
            const preNode = arr[index - 1];
            await updateCategoryTreeNodeSort({
                maxId: node.key,
                maxSortNo: node.sortNo,
                minId: preNode.key,
                minSortNo: preNode.sortNo
            });
            // 对调两节点位置
            let { isFirst, isLast } = preNode;
            preNode.isFirst = node.isFirst;
            preNode.isLast = node.isLast;
            node.isFirst = isFirst;
            node.isLast = isLast;
            arr[index] = preNode;
            arr[index - 1] = node;
            this.expandedKeys = [...this.expandedKeys];
        },
        async downNode(item) {
            const res = queryNodeInTree(item.key, { children: this.treeData });
            if (!res) {
                throw Error('未找到节点！', item);
            }
            const arr = res.pNode.children;
            const index = arr.findIndex(i => i.key == item.key);
            const node = arr[index];
            const nextNode = arr[index + 1];

            await updateCategoryTreeNodeSort({
                maxId: nextNode.key,
                maxSortNo: nextNode.sortNo,
                minId: node.key,
                minSortNo: node.sortNo
            });


            // 对调两节点位置
            let { isFirst, isLast } = nextNode;
            nextNode.isFirst = node.isFirst;
            nextNode.isLast = node.isLast;
            node.isFirst = isFirst;
            node.isLast = isLast;
            arr[index] = nextNode;
            arr[index + 1] = node;
            this.expandedKeys = [...this.expandedKeys];
        },
        handleCancel(){
            this.visible = false;
        },
        handleOk(){
            if (this.onOk) {
                this.onOk(this.selectedData);
            }
            this.visible = false;
        }
    }
}
/**
 * 节点数据转换为视图节点数据
 * @param {Array} nodeDatas
 */
function nodeDataToVMNodeData(nodeDatas,ctx) {
    const { canSelectedLevels } = ctx;
    return nodeDatas.map((i, index) => {
        if (i.children) {
            i.children = nodeDataToVMNodeData(i.children,ctx);
        }
        Object.assign(i, {
            title: i.areaName,
            key: i.id,
            scopedSlots: { title: 'custom' },
            isFirst: index == 0 ? true : false,
            isLast: index == nodeDatas.length - 1 ? true : false,
            // 是否是叶子节点
            isLeaf: i.level == canSelectedLevels[canSelectedLevels.length-1]
        });
        return i;
    })
}

/**
 * 树中查询节点
 * @returns {{
        node: item,
        pNode: tree
   }}
 */
function queryNodeInTree(key, tree) {
    if (!tree.children) {
        return null;
    }
    if (tree.children.length == 0) {
        return null;
    }
    const item = tree.children.find(i => i.key == key);
    if (item) {
        return {
            node: item,
            pNode: tree
        };
    }
    const arr = tree.children.map(i => queryNodeInTree(key, i));
    return arr.find(i => i != null);
}
</script>